iT邦幫忙

2022 iThome 鐵人賽

DAY 17
0

今天我們來聊聊一個開發中可以用到的工具:Middleware

根據官網所說:

Middleware provide a convenient mechanism for inspecting and filtering HTTP requests entering your application. For example, Laravel includes a middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware will redirect the user to your application's login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application.

換個說法,Middleware 就像是個過濾器一樣,可以過濾送進來的請求。

要新建 Middleware,我們一樣是透過 artisan

./vendor/bin/sail artisan make:middleware MyMiddleware

跑完之後,我們可以在 app/Http/Middleware/MyMiddleware.php 看到

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class MyMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
     * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
     */
    public function handle(Request $request, Closure $next)
    {
        return $next($request);
    }
}

這邊就是過濾的內容了,我們可以設置一些過濾條件,如果不符合條件就處理掉,然後將通過的請求往下一層送。

要套用規則的話,可以這樣寫

use App\Http\Middleware\MyMiddleware;
 
Route::get('/', function () {
    //
})->middleware(MyMiddleware::class);

我們實際來看看 Laravel 幫我們寫好的一些 Middleware

app/Http/Kernel.php 裡面,已經定義了很多我們可以使用在網頁開發上的 Middleware

/**
 * The application's route middleware.
 *
 * These middleware may be assigned to groups or used individually.
 *
 * @var array<string, class-string|string>
 */
protected $routeMiddleware = [
	'auth' => \App\Http\Middleware\Authenticate::class,
	'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
	'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
	'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
	'can' => \Illuminate\Auth\Middleware\Authorize::class,
	'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
	'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
	'signed' => \App\Http\Middleware\ValidateSignature::class,
	'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
	'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];

我們挑 Authenticate 這個來看看,打開 app/Http/Middleware/Authenticate.php

<?php

namespace App\Http\Middleware;

use Illuminate\Auth\Middleware\Authenticate as Middleware;

class Authenticate extends Middleware
{
    /**
     * Get the path the user should be redirected to when they are not authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return string|null
     */
    protected function redirectTo($request)
    {
        if (! $request->expectsJson()) {
            return route('login');
        }
    }
}

奇怪!內容怎麼這麼少?這裡面的內容顯然不能完成驗證用戶的功能呀?

這是因為,Laravel 這邊的作法,是將驗證用戶主要的程式碼,放在框架套件的程式碼 Illuminate\Auth\Middleware\Authenticate 裡面,然後 App\Http\Middleware\Authenticate 這個類別透過繼承 Illuminate\Auth\Middleware\Authenticate,可以使用裡面的內容,然後根據開發者的需要,對裡面的內容進行調整,比方說這邊的調整登入失敗時要導向的路徑為何。

這樣的設計,可以避免開發者需要調整功能時,必須要調整 Illuminate 裡面的程式碼,才能客製化自己想要的功能。

如果想繼續看 Illuminate\Auth\Middleware\Authenticate 的程式碼,那麼就是要到 vendor 資料夾裡面找了

vendor/laravel/freamework/src/Illuminate/Auth/Middleware/Authenticate.php

/**
 * Determine if the user is logged in to any of the given guards.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  array  $guards
 * @return void
 *
 * @throws \Illuminate\Auth\AuthenticationException
 */
protected function authenticate($request, array $guards)
{
	if (empty($guards)) {
		$guards = [null];
	}

	foreach ($guards as $guard) {
		if ($this->auth->guard($guard)->check()) {
			return $this->auth->shouldUse($guard);
		}
	}

	$this->unauthenticated($request, $guards);
}

我們就可以開始找到過濾的規則所撰寫的位置了。

看到這邊,有些讀者可能已經想到,Laravel 所提供的這些 Middleware,像是用戶的 Authenticate,似乎在我們前面的一些地方已經被套用過了?

沒錯!其實 Laravel 在一開始的時候,就已經預先幫我們加上一些 Middleware 的處理了!

我們可以在 app/Http/Kernel.php 裡面找到

protected $middlewareGroups = [
	'web' => [
		\App\Http\Middleware\EncryptCookies::class,
		\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
		\Illuminate\Session\Middleware\StartSession::class,
		\Illuminate\View\Middleware\ShareErrorsFromSession::class,
		\App\Http\Middleware\VerifyCsrfToken::class,
		\Illuminate\Routing\Middleware\SubstituteBindings::class,
	],

	'api' => [
		// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
		'throttle:api',
		\Illuminate\Routing\Middleware\SubstituteBindings::class,
	],
];

這段就是 Laravel 預先設置好的 Middleware 群組

其中 web 會被套用在 web.php 裡面的所有路由中。 api 會被套用在 api.php 的所有路由中。

這也就是 Laravel 實作許多功能,比方說 CSRF Token 驗證,所採取的作法。

今天對 Middleware 的介紹,就先到這邊。各位明天見!


上一篇
Day 16:另一種多語系的方式:談使用 json 處理多語系
下一篇
Day 18:網站常用的寄信功能:Laravel 寄送 email 的開發與測試
系列文
Laravel 9 漫遊,享受魔法般的極速網頁開發體驗30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言